﻿#include "stdafx.h"
#include "CMeasureObj.h"
#include "CBaseImage.h"
#include "CDisplayerUI.h"

using namespace Gdiplus;

CMeasureObj::CMeasureObj(CBaseImage* pImg, const DrawParam& param)
	: m_pImg(pImg)
	, m_bComplete(FALSE)
	, m_bSel(FALSE)
	, m_hDC(NULL)
	, m_nFontSize(10)
	, m_nHitState(-1)
	, m_bUpdateText(FALSE)
	, m_Font(_T("宋体"))
{
	m_drawInfo = param;
	m_bDrawLink = TRUE;
}

CMeasureObj::~CMeasureObj()
{

}

void CMeasureObj::Draw(HDC hDC, RECT rc, const DrawParam& param)
{
	m_hDC = hDC;
	m_rc = rc;
	m_drawInfo = param;
	
	Graphics gs(hDC);
	gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
	
	Matrix* mtx;
	mtx = m_drawInfo.GetMatrix(m_rc);
	gs.SetTransform(mtx);
	DrawShape(gs, rc, param);
	gs.ResetTransform();

	DrawText(gs);
	DrawLinkLine(gs);
}

Gdiplus::RectF CMeasureObj::GetPtRect(Gdiplus::PointF pt, BOOL isClient/* = FALSE*/)
{
	RectF rcPt;
	int nDelta = 4;

	if (!isClient)
		pt = ImageToClient(pt);

	rcPt.X = pt.X - nDelta;
	rcPt.Y = pt.Y - nDelta;
	rcPt.Width = nDelta * 2;
	rcPt.Height = nDelta * 2;

	return rcPt;
}

Gdiplus::PointF CMeasureObj::ImageToClient(Gdiplus::PointF ptI)
{
	//PointF ptC(ptI);
	//if (m_pImg == NULL)
	//	return ptC;

	//ptC.X *= m_drawInfo.zoom;
	//ptC.Y *= m_drawInfo.zoom;

	//float dw, dh;
	//dw = m_drawInfo.width * m_drawInfo.zoom;
	//dh = m_drawInfo.height * m_drawInfo.zoom;

	//PointF ptOrg;
	//ptOrg.X = (m_rc.right - m_rc.left - dw) / 2 + m_rc.left + m_drawInfo.nOffsetX;
	//ptOrg.Y = (m_rc.bottom - m_rc.top - dh) / 2 + m_rc.top + m_drawInfo.nOffsetY;

	//ptC.X += ptOrg.X;
	//ptC.Y += ptOrg.Y;

	//return ptC;

	PointF ptC(ptI);

	Matrix* mtx = m_drawInfo.GetMatrix(m_rc);
	mtx->TransformPoints(&ptC, 1);

	return ptC;

}

int CMeasureObj::HitTest(PointF pt, BOOL bPress)
{
	int val = -1;
	return val;
}

int CMeasureObj::Move(float offseX, float offseY)
{
	if (m_nHitState == -1)
		return -1;

	int mtype = GetClassType();

	if (m_nHitState < 4)
	{
		m_vecPoints[m_nHitState].X += offseX;
		m_vecPoints[m_nHitState].Y += offseY;
		if (mtype == MT_RECT || mtype == MT_ELLIPSE 
			|| mtype == TT_TEXT || mtype == TT_L || mtype == TT_R)
		{
			switch (m_nHitState)
			{
			case 0:
				m_vecPoints[2].Y = m_vecPoints[0].Y;
				m_vecPoints[3].X = m_vecPoints[0].X;
				break;
			case 1:
				m_vecPoints[2].X = m_vecPoints[1].X;
				m_vecPoints[3].Y = m_vecPoints[1].Y;
				break;
			case 2:
				m_vecPoints[0].Y = m_vecPoints[2].Y;
				m_vecPoints[1].X = m_vecPoints[2].X;
				break;
			case 3:
				m_vecPoints[0].X = m_vecPoints[3].X;
				m_vecPoints[1].Y = m_vecPoints[3].Y;
				break;
			}

			NormalizeRect(m_vecPoints);
		}
		m_bUpdateText = TRUE;
	}
	else if (4 == m_nHitState)
	{
		for (size_t i = 0; i < m_vecPoints.size(); i++)
		{
			m_vecPoints[i].X += offseX;
			m_vecPoints[i].Y += offseY;
		}

		if (mtype == MT_POINT|| mtype == MT_RECT || mtype == MT_ELLIPSE || mtype == MT_CURVE)
			m_bUpdateText = TRUE;
	}
	else if (5 == m_nHitState)
	{
		m_ptTextOrigin.X += offseX;
		m_ptTextOrigin.Y += offseY;
	}

	return m_nHitState;
}

void CMeasureObj::DrawCross(Gdiplus::Graphics& gs, Gdiplus::PointF pt, Gdiplus::Color color)
{
	int nDelta = 4;

	Pen pen(color);
	gs.DrawLine(&pen, pt.X - nDelta, pt.Y, pt.X + nDelta, pt.Y);
	gs.DrawLine(&pen, pt.X, pt.Y - nDelta, pt.X, pt.Y + nDelta);
}

void CMeasureObj::DrawText(Gdiplus::Graphics& gs)
{
	int num = m_vecText.size();
	if (num <= 0)
		return;

	Font font(L"宋体", m_nFontSize);
	//RectF rcTxt = GetTextRect(m_vecText.at(0), m_ptTextOrigin, &font);


	PointF ptWork(m_ptTextOrigin.X, m_ptTextOrigin.Y);
	ptWork = ImageToClient(ptWork);
	ptWork.X += 4;

	m_rcText.X = ptWork.X;
	m_rcText.Y = ptWork.Y;
	m_rcText.Width = 0;
	m_rcText.Height = 0;

	for (int i=0; i<num; i++)
	{
		DString txt = m_vecText.at(i);
		RectF rc;
		rc = GetTextRect(txt, ptWork, &font);
		m_rcText.Width = rc.Width > m_rcText.Width ? rc.Width : m_rcText.Width;
		m_rcText.Height += rc.Height;
	}

	if (num > 1)
	{
		m_rcText.Offset(0, -m_rcText.Height / 2);
		m_rcText.GetLocation(&ptWork);
	}

	SolidBrush brBg(colorTextbg);
	if (m_nHitState != -1)
		brBg.SetColor(colorTextbgHover);

	gs.FillRectangle(&brBg, m_rcText);

	SolidBrush brTxt(colorText);

	for (int i=0; i<num; i++)
	{
		DString txt = m_vecText.at(i);
		RectF rc;
		rc = GetTextRect(txt, ptWork, &font);
		gs.DrawString(txt.GetData(), txt.GetLength(), &font, ptWork, &brTxt);
		ptWork.Y += rc.Height;
	}
}


void CMeasureObj::DrawLinkLine(Gdiplus::Graphics& gs)
{
	if (m_vecText.size() < 1)
		return;

	if (!m_bDrawLink)
		return;

	Pen pen(colorGreen);
	pen.SetDashStyle(Gdiplus::DashStyleDash);

	//PointF ptB(m_ptTextLink);
	PointF ptB(ImageToClient(m_ptTextLink));
	gs.DrawLine(&pen, ptB, PointF(m_rcText.X, m_rcText.Y));
}

void CMeasureObj::FormatFloatValue(float fVal, DString& str)
{
	if (fVal >= 10000)
	{
		// 如果整数部分占5位以上，则只显示整数部分
		str.Format(_T("%.0f"), fVal);
	}
	else if (fVal >= 1000 && fVal < 10000)
	{
		// 如果整数部分占4位，则显示1位小数
		str.Format(_T("%4.1f"), fVal);
	}
	else if (fVal >= 100 && fVal < 1000)
	{
		// 如果整数部分占3位，则显示2位小数
		str.Format(_T("%3.2f"), fVal);
	}
	else if (fVal >= 10 && fVal < 100)
	{
		// 如果整数部分占2位，则显示3位小数
		str.Format(_T("%2.3f"), fVal);
	}
	else
	{
		// 如果整数部分占1位，则显示4位小数
		str.Format(_T("%1.4f"), fVal);
	}

	// 如果小数部分全部为0，则去掉
	int nPtPos = str.Find(_T("."));
	if (nPtPos != -1)
	{
		DString strTemp = str.Right(str.GetLength() - nPtPos - 1);
		int nTemp = _ttoi(strTemp);
		if (nTemp == 0)
		{
			str = str.Left(nPtPos);
		}
	}
}

BOOL CMeasureObj::IsInHandle(Gdiplus::PointF ptHandle, Gdiplus::PointF pt)
{
	int nDelta = 4;

	RectF rc;
	rc.X = ptHandle.X - nDelta;
	rc.Y = ptHandle.Y - nDelta;
	rc.Width = rc.X + nDelta * 2;
	rc.Height = rc.Y + nDelta * 2;

	BOOL bIn = FALSE;

	if (rc.Contains(pt))
		bIn = TRUE;

	return bIn;
}

void CMeasureObj::NormalizeRect(vector<PointF>& pts)
{
	PointF ptB, ptE, ptRT, ptLB;
	PointF pt0 = pts.at(0);
	PointF pt1 = pts.at(1);
	ptB.X = pt0.X < pt1.X ? pt0.X : pt1.X;
	ptB.Y = pt0.Y < pt1.Y ? pt0.Y : pt1.Y;
	ptE.X = pt0.X > pt1.X ? pt0.X : pt1.X;
	ptE.Y = pt0.Y > pt1.Y ? pt0.Y : pt1.Y;

	m_ptTextLink = ptE;

	ptRT.X = ptE.X; ptRT.Y = ptB.Y;
	ptLB.X = ptB.X; ptLB.Y = ptE.Y;

	pts.clear();
	pts.push_back(ptB);
	pts.push_back(ptE);
	pts.push_back(ptRT);
	pts.push_back(ptLB);
}

float CMeasureObj::GetDistance(const PointF& pt1, const PointF& pt2, float psX, float psY)
{
	float disx = pt1.X - pt2.X;
	float disy = pt1.Y - pt2.Y;

	if (m_pImg)
	{
		psX = m_pImg->GetImageInfo().psX;
		psY = m_pImg->GetImageInfo().psY;
	}

	float dist = 0.0;
	
	if (psX == 1.0 && psY == 1.0)
	{
		dist = sqrtf(disx*disx + disy*disy);
	}
	else
	{
		dist = sqrtf(disx*disx*psY*psY + disy*disy*psX*psX);
	}

	return dist;
}

float CMeasureObj::GetAngle(const PointF& pt1, const PointF& pt2, const PointF& pt3)
{
	float ma_x = pt1.X - pt2.X;
	float ma_y = pt1.Y - pt2.Y;
	float mb_x = pt3.X - pt2.X;
	float mb_y = pt3.Y - pt2.Y;
	float v1 = (ma_x * mb_x) + (ma_y * mb_y);
	float ma_val = sqrt(ma_x*ma_x + ma_y * ma_y);
	float mb_val = sqrt(mb_x*mb_x + mb_y * mb_y);
	float cosM = v1 / (ma_val*mb_val);
	float angleAMB = acos(cosM) * 180 / M_PI;

	return angleAMB;
}

Gdiplus::RectF CMeasureObj::GetTextRect(DString txt, Gdiplus::PointF ptOrg, Gdiplus::Font* font)
{
	RectF rcText;
	if (m_hDC == NULL)
		return rcText;

	Graphics gs(m_hDC);
	gs.MeasureString(txt.GetData(), txt.GetLength(), font, ptOrg, &rcText);

	return rcText;
}

float CMeasureObj::GetLineLen(const Gdiplus::PointF& pt1, const Gdiplus::PointF& pt2)
{
	float disx = pt1.X - pt2.X;
	float disy = pt1.Y - pt2.Y;
	float num = (disx * disx) + (disy * disy);
	return sqrt(num);
}

CMeasurePoint::CMeasurePoint(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{

}


void CMeasurePoint::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	m_rc = rc;
	m_drawInfo = param;

	PointF ptI = m_vecPoints.at(0);

	//PointF ptC = ptI;
	//RectF rcPoint;
	//rcPoint.X = ptC.X - 2;
	//rcPoint.Y = ptC.Y - 2;
	//rcPoint.Width = 4;
	//rcPoint.Height = 4;

	Pen pen(colorGreen);

	if (m_nHitState == 0)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	//gs.DrawEllipse(&pen, rcPoint);
	Color pencolor;
	pen.GetColor(&pencolor);
	DrawCross(gs, ptI, pencolor);

	m_ptTextLink.X = ptI.X + 4;
	m_ptTextLink.Y = ptI.Y + 4;

	if (!m_bComplete)
		m_ptTextOrigin = m_ptTextLink;

	// 文字
	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}

}

LPCTSTR CMeasurePoint::GetClass()
{
	return _T("MeasurePoint");
}

int CMeasurePoint::GetClassType()
{
	return MT_POINT;
}

void CMeasurePoint::GetText()
{
	if (m_vecPoints.size() <= 0)
		return;

	m_vecText.clear();

	PointF ptI = m_vecPoints.at(0);

	MeasureInfo minfo;
	m_pImg->GetMeasureInfo(minfo, 0, &m_vecPoints);
	DString txt;

	DString strMinVal;
	FormatFloatValue(minfo.minVal, strMinVal);

	txt.Format(_T("X:%d,Y:%d Val:%s"), (int)ptI.X, (int)ptI.Y, strMinVal.GetData());
	m_vecText.push_back(txt);
}

int CMeasurePoint::HitTest(PointF pt, BOOL bPress)
{
	RectF rcPt = GetPtRect(m_vecPoints.at(0));

	m_nHitState = -1;

	if (rcPt.Contains(pt))
	{
		m_nHitState = 0;
		if (bPress)
		{
			m_bSel = bPress;
			m_nHitState = 4;
		}
			
		return m_nHitState;
	}

	if (m_rcText.Contains(pt))
	{
		m_nHitState = 5;
		return m_nHitState;
	}
		
	return m_nHitState;
}

CMeasureLine::CMeasureLine(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{

}


void CMeasureLine::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	if (m_vecPoints.size() < 2)
		return;

	m_rc = rc;
	m_drawInfo = param;

	PointF pt0 = m_vecPoints.at(0);
	PointF pt1 = m_vecPoints.at(1);
	//PointF ptC1 = ImageToClient(pt0);
	//PointF ptC2 = ImageToClient(pt1);
	PointF ptC1(pt0);
	PointF ptC2(pt1);
	
	Pen pen(colorGreen);
	Pen penPin(colorRed);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	gs.DrawLine(&pen, ptC1, ptC2);

	// 两个端点十字
	for (size_t i=0; i<m_vecPoints.size(); i++)
	{
		//PointF ptC = ImageToClient(m_vecPoints.at(i));
		PointF ptC(m_vecPoints.at(i));

		Color color(colorRed);
		if (m_nHitState == i)
			color = colorHover;
		DrawCross(gs, ptC, color);
	}

	// 文字
	m_ptTextLink.X = pt0.X > pt1.X ? pt0.X : pt1.X;
	m_ptTextLink.Y = pt0.X > pt1.X ? pt0.Y : pt1.Y;

	if (!m_bComplete)
	{
		m_ptTextOrigin = m_ptTextLink;
	}
	
	
	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}
	

}

LPCTSTR CMeasureLine::GetClass()
{
	return _T("MeasureLine");
}

int CMeasureLine::GetClassType()
{
	return MT_LINE;
}

void CMeasureLine::GetText()
{
	if (m_vecPoints.size() < 2)
		return;

	m_vecText.clear();

	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;
	float dist = GetDistance(m_vecPoints.at(0), m_vecPoints.at(1), psX, psY);

	DString txt;
	if (dist > 100)
		txt.Format(_T("%.2fcm"), dist / 10.0);
	else
		txt.Format(_T("%.1fmm"), dist);

	m_vecText.push_back(txt);
}

int CMeasureLine::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	m_nHitState = -1;
	for (size_t i=0; i<m_vecPoints.size(); i++)
	{
		RectF rc = GetPtRect(m_vecPoints.at(i));
		if (rc.Contains(pt))
		{
			m_nHitState = i;
			return m_nHitState;
		}
	}

	if (m_vecPoints.size() >= 2)
	{
		PointF ptB = m_vecPoints.at(0);
		PointF ptE = m_vecPoints.at(1);
		ptB = ImageToClient(ptB);
		ptE = ImageToClient(ptE);

		if (GetLineLen(ptB, pt) + GetLineLen(pt, ptE) - GetLineLen(ptB, ptE) < 1)
		{
			m_nHitState = 4;
			if (bPress)
				m_bSel = bPress;
			return m_nHitState;
		}
	}

	//PointF ptI = CDisplayerUI::ClientToImage(m_rc, m_drawInfo, pt);
	if (m_rcText.Contains(pt))
	{
		m_nHitState = 5;
		return m_nHitState;
	}
	

	return m_nHitState;
}

CMeasureAngle::CMeasureAngle(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{

}

void CMeasureAngle::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	int num = m_vecPoints.size();
	if (num < 2)
		return;

	m_rc = rc;
	m_drawInfo = param;

	Pen pen(colorGreen);
	Pen penPin(colorRed);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	PointF ptC1(m_vecPoints.at(0));
	PointF ptC2(m_vecPoints.at(1));
	gs.DrawLine(&pen, ptC1, ptC2);

	if (num > 2)
	{
		ptC1 = m_vecPoints.at(2);
		gs.DrawLine(&pen, ptC2, ptC1);
	}

	// 两个端点十字
	for (size_t i = 0; i < m_vecPoints.size(); i++)
	{
		PointF ptC = m_vecPoints.at(i);

		Color color(colorRed);
		if (m_nHitState == i)
			color = colorHover;
		DrawCross(gs, ptC, color);
	}

	// 文字
	if (num < 3) return;

	PointF ptI = m_vecPoints.at(1);
	m_ptTextLink.X = ptI.X + 2;
	m_ptTextLink.Y = ptI.Y + 2;

	if (!m_bComplete)
	{
		m_ptTextOrigin = m_ptTextLink;
	}

	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}
	
}

LPCTSTR CMeasureAngle::GetClass()
{
	return _T("MeasureAngle");
}

int CMeasureAngle::GetClassType()
{
	return MT_ANGLE;
}

void CMeasureAngle::GetText()
{
	if (m_vecPoints.size() < 3)
		return;

	m_vecText.clear();

	DString txt;
	PointF pt1 = m_vecPoints.at(0);
	PointF pt2 = m_vecPoints.at(1);
	PointF pt3 = m_vecPoints.at(2);
	float angle = GetAngle(pt1, pt2, pt3);
	txt.Format(_T("%.1f°"), angle);
	m_vecText.push_back(txt);
}

void CMeasureAngle::Complete(Gdiplus::PointF pt)
{
	if (m_vecPoints.size() >= 3)
	{
		m_vecPoints[2] = pt;
		m_bComplete = TRUE;
	}
		
}

int CMeasureAngle::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	m_nHitState = -1;
	for (size_t i = 0; i < m_vecPoints.size(); i++)
	{
		RectF rc = GetPtRect(m_vecPoints.at(i));
		if (rc.Contains(pt))
		{
			m_nHitState = i;
			return m_nHitState;
		}
	}

	if (m_vecPoints.size() >= 3)
	{
		PointF pt0 = m_vecPoints.at(0);
		PointF pt1 = m_vecPoints.at(1);
		PointF pt2 = m_vecPoints.at(2);
		pt0 = ImageToClient(pt0);
		pt1 = ImageToClient(pt1);
		pt2 = ImageToClient(pt2);

		if ((GetLineLen(pt0, pt) + GetLineLen(pt, pt1) - GetLineLen(pt0, pt1) < 1)
			|| (GetLineLen(pt1, pt) + GetLineLen(pt, pt2) - GetLineLen(pt1, pt2) < 1))
		{
			m_nHitState = 4;
			if (bPress)
				m_bSel = bPress;
			return m_nHitState;
		}
	}

	if (m_rcText.Contains(pt))
	{
		m_nHitState = 5;
		//m_bSel = bPress;
		return m_nHitState;
	}

	return m_nHitState;
}

CMeasureRect::CMeasureRect(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{

}


void CMeasureRect::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	int num = m_vecPoints.size();
	if (num < 2)
		return;

	m_rc = rc;
	m_drawInfo = param;

	PointF ptB, ptE, ptRT, ptLB;
	PointF pt0 = m_vecPoints.at(0);
	PointF pt1 = m_vecPoints.at(1);
	ptB.X = pt0.X < pt1.X ? pt0.X : pt1.X;
	ptB.Y = pt0.Y < pt1.Y ? pt0.Y : pt1.Y;
	ptE.X = pt0.X > pt1.X ? pt0.X : pt1.X;
	ptE.Y = pt0.Y > pt1.Y ? pt0.Y : pt1.Y;

	m_ptTextLink = ptE;

	//ptB = ImageToClient(ptB);
	//ptE = ImageToClient(ptE);

	ptRT.X = ptE.X; ptRT.Y = ptB.Y;
	ptLB.X = ptB.X; ptLB.Y = ptE.Y;

	m_vecCross.clear();
	m_vecCross.push_back(ptB);
	m_vecCross.push_back(ptE);
	m_vecCross.push_back(ptRT);
	m_vecCross.push_back(ptLB);

	Pen pen(colorGreen);
	Pen penPin(colorRed);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	RectF rcRect;
	rcRect.X = ptB.X;
	rcRect.Y = ptB.Y;
	rcRect.Width = ptE.X - ptB.X;
	rcRect.Height = ptE.Y - ptB.Y;

	gs.DrawRectangle(&pen, rcRect);

	// 端点十字
	for (size_t i = 0; i < m_vecCross.size(); i++)
	{
		PointF ptC = m_vecCross.at(i);

		Color color(colorRed);
		if (m_nHitState == i)
			color = colorHover;
		DrawCross(gs, ptC, color);
	}

	// 文字
	if (!m_bComplete)
	{
		m_ptTextOrigin = m_ptTextLink;
	}

	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}
	

}

LPCTSTR CMeasureRect::GetClass()
{
	return _T("MeasureRect");
}

int CMeasureRect::GetClassType()
{
	return MT_RECT;
}

void CMeasureRect::GetText()
{
	if (m_vecPoints.size() < 2)
		return;

	m_vecText.clear();

	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;
	float dist = GetDistance(m_vecPoints.at(0), m_vecPoints.at(1), psX, psY);

	MeasureInfo minfo;
	m_pImg->GetMeasureInfo(minfo, 1, &m_vecPoints);

	DString sdTxt, valTxt, aTxt, str1, str2;
	FormatFloatValue(minfo.meanVal, str1);
	FormatFloatValue(minfo.stddev, str2);

	sdTxt.Format(_T("Mean=%s SD=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(sdTxt);

	str1 = _T("");
	str2 = _T("");
	FormatFloatValue(minfo.maxVal, str1);
	FormatFloatValue(minfo.minVal, str2);

	valTxt.Format(_T("Max=%s Min=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(valTxt);

	aTxt.Format(_T("Area=%.2f cm²(%d px)"), minfo.area/100, minfo.pxCount);
	m_vecText.push_back(aTxt);

}


void CMeasureRect::Complete(Gdiplus::PointF pt)
{
	if (m_vecPoints.size() < 2)
		return;

	CMeasureObj::Complete(pt);
	m_bUpdateText = TRUE;

	NormalizeRect(m_vecPoints);
}

int CMeasureRect::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	m_nHitState = -1;
	for (size_t i = 0; i < m_vecPoints.size(); i++)
	{
		RectF rc = GetPtRect(m_vecPoints.at(i));
		if (rc.Contains(pt))
		{
			m_nHitState = i;
			return m_nHitState;
		}
	}

	if (m_vecPoints.size() >= 4)
	{
		PointF ptB = ImageToClient(m_vecPoints.at(0));
		PointF ptE = ImageToClient(m_vecPoints.at(1));
		RectF rcRect;
		rcRect.X = ptB.X;
		rcRect.Y = ptB.Y;
		rcRect.Width = ptE.X - ptB.X;
		rcRect.Height = ptE.Y - ptB.Y;

		if (rcRect.Contains(pt))
		{
			m_nHitState = 4;
			if (bPress)
				m_bSel = bPress;
			return m_nHitState;
		}
	}

	if (m_rcText.Contains(pt))
	{
		m_nHitState = 5;
		//m_bSel = bPress;
		return m_nHitState;
	}

	return m_nHitState;
}

CMeasureEllipse::CMeasureEllipse(CBaseImage* pImg, const DrawParam& param)
	: CMeasureRect(pImg, param)
{

}


void CMeasureEllipse::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	int num = m_vecPoints.size();
	if (num < 2)
		return;

	m_rc = rc;
	m_drawInfo = param;

	PointF ptB, ptE, ptRT, ptLB;
	PointF pt0 = m_vecPoints.at(0);
	PointF pt1 = m_vecPoints.at(1);
	ptB.X = pt0.X < pt1.X ? pt0.X : pt1.X;
	ptB.Y = pt0.Y < pt1.Y ? pt0.Y : pt1.Y;
	ptE.X = pt0.X > pt1.X ? pt0.X : pt1.X;
	ptE.Y = pt0.Y > pt1.Y ? pt0.Y : pt1.Y;

	m_ptTextLink = ptE;

	//ptB = ImageToClient(ptB);
	//ptE = ImageToClient(ptE);
	ptRT.X = ptE.X; ptRT.Y = ptB.Y;
	ptLB.X = ptB.X; ptLB.Y = ptE.Y;

	m_vecCross.clear();
	m_vecCross.push_back(ptB);
	m_vecCross.push_back(ptE);
	m_vecCross.push_back(ptRT);
	m_vecCross.push_back(ptLB);

	Pen pen(colorGreen);
	Pen penPin(colorRed);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	RectF rcRect;
	rcRect.X = ptB.X;
	rcRect.Y = ptB.Y;
	rcRect.Width = ptE.X - ptB.X;
	rcRect.Height = ptE.Y - ptB.Y;

	gs.DrawEllipse(&pen, rcRect);

	// 端点十字
	for (size_t i = 0; i < m_vecCross.size(); i++)
	{
		PointF ptC = m_vecCross.at(i);

		Color color(colorRed);
		if (m_nHitState == i)
			color = colorHover;
		DrawCross(gs, ptC, color);
	}

	// 文字
	if (!m_bComplete)
	{
		m_ptTextOrigin = m_ptTextLink;
	}

	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}
	
}

LPCTSTR CMeasureEllipse::GetClass()
{
	return _T("MeasureEllipse");
}

int CMeasureEllipse::GetClassType()
{
	return MT_ELLIPSE;
}

void CMeasureEllipse::GetText()
{
	if (m_vecPoints.size() < 2)
		return;

	m_vecText.clear();

	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;
	float dist = GetDistance(m_vecPoints.at(0), m_vecPoints.at(1), psX, psY);

	MeasureInfo minfo;
	m_pImg->GetMeasureInfo(minfo, 2, &m_vecPoints);

	DString sdTxt, valTxt, aTxt, str1, str2;
	FormatFloatValue(minfo.meanVal, str1);
	FormatFloatValue(minfo.stddev, str2);

	sdTxt.Format(_T("Mean=%s SD=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(sdTxt);

	str1 = _T("");
	str2 = _T("");
	FormatFloatValue(minfo.maxVal, str1);
	FormatFloatValue(minfo.minVal, str2);

	valTxt.Format(_T("Max=%s Min=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(valTxt);

	aTxt.Format(_T("Area=%.2f cm²(%d px)"), minfo.area / 100, minfo.pxCount);
	m_vecText.push_back(aTxt);
}


CMeasureCurve::CMeasureCurve(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{

}


void CMeasureCurve::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	m_rc = rc;
	m_drawInfo = param;

	int num = m_vecPoints.size();

	m_ptTextLink = PointF(0,0);
	PointF *pts;
	pts = new PointF[num];

	for (int i = 0; i < num; ++i)
	{
		pts[i] = m_vecPoints[i];
		m_ptTextLink.X = m_vecPoints[i].X > m_ptTextLink.X ? m_vecPoints[i].X : m_ptTextLink.X;
		m_ptTextLink.Y = m_vecPoints[i].Y > m_ptTextLink.Y ? m_vecPoints[i].Y : m_ptTextLink.Y;
	}

	Pen pen(colorGreen);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	gs.DrawPolygon(&pen, pts, num);

	// 文字
	if (!m_bComplete)
	{
		m_ptTextOrigin = m_ptTextLink;
	}

	if (m_bUpdateText || m_vecText.size()==0)
	{
		GetText();
		m_bUpdateText = FALSE;
	}
	
}

LPCTSTR CMeasureCurve::GetClass()
{
	return _T("MeasureCurve");
}

int CMeasureCurve::GetClassType()
{
	return MT_CURVE;
}

void CMeasureCurve::GetText()
{
	if (!m_bComplete)
		return;

	m_vecText.clear();

	// ²
	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;
	float dist = GetDistance(m_vecPoints.at(0), m_vecPoints.at(1), psX, psY);

	MeasureInfo minfo;
	m_pImg->GetMeasureInfo(minfo, 3, &m_vecPoints);

	DString sdTxt, valTxt, aTxt, str1, str2;

	str1 = _T("");
	str2 = _T("");
	FormatFloatValue(minfo.meanVal, str1);
	FormatFloatValue(minfo.stddev, str2);

	sdTxt.Format(_T("Mean=%s SD=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(sdTxt);

	str1 = _T("");
	str2 = _T("");
	FormatFloatValue(minfo.maxVal, str1);
	FormatFloatValue(minfo.minVal, str2);

	valTxt.Format(_T("Max=%s Min=%s"), str1.GetData(), str2.GetData());
	m_vecText.push_back(valTxt);

	aTxt.Format(_T("Area=%.2f cm²(%d px)"), minfo.area/100, minfo.pxCount);
	m_vecText.push_back(aTxt);
}

void CMeasureCurve::Complete(Gdiplus::PointF pt)
{
	if (m_vecPoints.size() < 3)
		return;

	m_bComplete = TRUE;
	m_vecPoints.push_back(pt);
	PointF ptFirst = m_vecPoints.at(0);
	m_vecPoints.push_back(ptFirst);
}

int CMeasureCurve::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	m_nHitState = -1;
	
	GraphicsPath path;
	Gdiplus::PointF *pts;

	int num = m_vecPoints.size();
	pts = new Gdiplus::PointF[num];
	for (int i = 0; i < num; ++i)
	{
		pts[i] = ImageToClient(m_vecPoints[i]);
	}

	path.AddPolygon(pts, num);
	Gdiplus::Region region(&path);

	if (region.IsVisible(pt))
	{
		m_nHitState = 4;
		if (bPress)
			m_bSel = bPress;
	}

	if (m_rcText.Contains(pt))
	{
		m_nHitState = 5;
		return m_nHitState;
	}

	return m_nHitState;
}

CMeasureCTR::CMeasureCTR(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
	, m_Line1(pImg, param)
	, m_Line2(pImg, param)
{
	m_bDrawLink = FALSE;
}


void CMeasureCTR::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	m_rc = rc;
	m_drawInfo = param;

	m_Line1.Draw(m_hDC, rc, param);
	m_Line2.Draw(m_hDC, rc, param);

	// 文字
	if (m_bUpdateText || m_vecText.size() == 0)
	{
		GetText();
		m_bUpdateText = TRUE;

		Font font(L"宋体", m_nFontSize);
		DString txt = m_vecText.at(0);
		RectF rcTxt = GetTextRect(txt, PointF(0, 0), &font);
		PointF pt, p0, p1;
		p0 = m_Line2.GetPoint(0);
		p1 = m_Line2.GetPoint(1);
		pt.X = (p1.X - p0.X - rcTxt.Width) / 2 + p0.X;
		pt.Y = (p1.Y - p0.Y - rcTxt.Height) / 2 + p0.Y;
		//m_ptTextLink = m_ptTextOrigin = CDisplayerUI::ClientToImage(m_rc, m_drawInfo, pt);
		m_ptTextLink = m_ptTextOrigin = pt;
	}

	
}

LPCTSTR CMeasureCTR::GetClass()
{
	return _T("MeasureCTR");
}

int CMeasureCTR::GetClassType()
{
	return MT_CTR;
}

void CMeasureCTR::GetText()
{
	m_vecText.clear();
	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;
	float dist1 = GetDistance(m_Line1.GetPoint(0), m_Line1.GetPoint(1), psX, psY);
	float dist2 = GetDistance(m_Line2.GetPoint(0), m_Line2.GetPoint(1), psX, psY);

	DString txt;
	txt.Format(_T("%.2f"), dist1/dist2);
	m_vecText.push_back(txt);
}

void CMeasureCTR::Complete(Gdiplus::PointF pt)
{
	m_bComplete = TRUE;
	m_Line1.Complete(pt);
	m_Line2.Complete(pt);
}

void CMeasureCTR::AddPoint(Gdiplus::PointF pt)
{
	PointF p0, p1, p2, p3;

	float psX = m_pImg->GetImageInfo().psX;
	float psY = m_pImg->GetImageInfo().psY;

	// 两线上下距离约10mm
	float dy = 60.0 / psY;

	// 心脏横径约100mm
	float cx = 100.0 / psX;

	// 心胸比约为0.43
	float cx2 = cx / 0.43;

	float posX = pt.X - cx2 / 2;
	float posY = pt.Y + dy + 10;
	p2.X = posX > 10 ? posX : 10;
	p2.X = p2.X > m_drawInfo.width/2 ? (m_drawInfo.width/2) : p2.X;
	p2.Y = posY > 10 ? posY : 10;
	p2.Y = p2.Y > m_drawInfo.height ? (m_drawInfo.height - 10) : p2.Y;

	p3.X = p2.X + cx2;
	p3.Y = p2.Y;

	p0.X = (p3.X - p2.X - cx) / 2 + p2.X;
	p0.Y = p2.Y - dy;

	p1.X = p0.X + cx;
	p1.Y = p0.Y;

	m_Line1.AddPoint(p0);
	m_Line1.AddPoint(p1);

	m_Line2.AddPoint(p2);
	m_Line2.AddPoint(p3);

}

int CMeasureCTR::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	m_nHitState = -1;

	m_nHitState = m_Line1.HitTest(pt, bPress);
	if (-1 == m_nHitState)
	{
		m_nHitState = m_Line2.HitTest(pt, bPress);
		if (4 == m_nHitState && bPress)
			m_Line1.SetSel(FALSE);
	}
	else if (4 == m_nHitState && bPress)
		m_Line2.SetSel(FALSE);

	return m_nHitState;
}

int CMeasureCTR::Move(float offseX, float offseY)
{
	m_Line1.Move(offseX, offseY);
	m_Line2.Move(offseX, offseY);

	return 0;
}

CShapeArrow::CShapeArrow(CBaseImage* pImg, const DrawParam& param)
	: CMeasureLine(pImg, param)
{
	
}

void CShapeArrow::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	int num = m_vecPoints.size();
	if (num < 2)
		return;

	Gdiplus::REAL lineWidth = 1.0;

	Pen penLine(Color(255, 0, 0), lineWidth);
	Pen penArrow(Color(255, 0, 0));
	SolidBrush brush_a(Color(255, 0, 0));

	PointF ptStart(m_vecPoints.at(0));
	PointF ptEnd(m_vecPoints.at(1));

	double distance = GetDistance(ptStart, ptEnd, 1.0, 1.0);
	const double minLen = 80.0, maxLen = 300;
	double l = 0.1;
	if (distance <= minLen)
	{
		l = (minLen * 0.1) / distance;
		DrawArrow(gs, ptStart, ptEnd, penArrow, brush_a, l);
	}
	else if (distance > maxLen)
	{
		l = (maxLen * 0.1) / distance;
		DrawArrow(gs, ptStart, ptEnd, penArrow, brush_a, l);
	}
	else
	{
		DrawArrow(gs, ptStart, ptEnd, penArrow, brush_a, l);
	}
}

LPCTSTR CShapeArrow::GetClass()
{
	return _T("ShapeArrow");
}

int CShapeArrow::GetClassType()
{
	return TT_ARROW;
}

void CShapeArrow::DrawArrow(Gdiplus::Graphics & gs, const Gdiplus::PointF & ptStart, const Gdiplus::PointF & ptEnd, 
	const Gdiplus::Pen & pen_a, const Gdiplus::Brush & brush_a, double percent)
{
	const double t = M_PI / 12;    //箭头与直线夹角
	const double ArrowPercent = 0.65;

	PointF ptArrowCw, ptArrowCCw;
	PointF ptStartCw/*直线一个端点顺时针旋转后的点的坐标*/, ptStartCCw/*直线一个端点逆时针旋转后的点的坐标*/;
	PointF ptInterArrowCw, ptInterArrowCCw;

	ptStartCw.X = (ptStart.X - ptEnd.X) * cos(t) - (ptStart.Y - ptEnd.Y) * sin(t);
	ptStartCw.Y = (ptStart.X - ptEnd.X) * sin(t) + (ptStart.Y - ptEnd.Y) * cos(t);
	ptArrowCw.X = percent * ptStartCw.X + ptEnd.X;
	ptArrowCw.Y = percent * ptStartCw.Y + ptEnd.Y;

	ptStartCCw.X = (ptStart.X - ptEnd.X) * cos(t) + (ptStart.Y - ptEnd.Y) * sin(t);
	ptStartCCw.Y = -(ptStart.X - ptEnd.X) * sin(t) + (ptStart.Y - ptEnd.Y) * cos(t);
	ptArrowCCw.X = percent * ptStartCCw.X + ptEnd.X;
	ptArrowCCw.Y = percent * ptStartCCw.Y + ptEnd.Y;

	ptInterArrowCw.X = (ptArrowCw.X - ptArrowCCw.X) * ArrowPercent + ptArrowCCw.X;//ptArrowCCw平移到窗口原点
	ptInterArrowCw.Y = (ptArrowCw.Y - ptArrowCCw.Y) * ArrowPercent + ptArrowCCw.Y;
	ptInterArrowCCw.X = (ptArrowCCw.X - ptArrowCw.X) * ArrowPercent + ptArrowCw.X;//ptArrowCCw平移到窗口原点
	ptInterArrowCCw.Y = (ptArrowCCw.Y - ptArrowCw.Y) * ArrowPercent + ptArrowCw.Y;


	PointF ptTriangle[] = { PointF(ptEnd.X, ptEnd.Y), ptArrowCCw, ptArrowCw };
	PointF ptTriangle2[] = { PointF(ptStart.X, ptStart.Y), ptInterArrowCw, ptInterArrowCCw };

	//graphics.DrawLine(&pen_a,PointF(ptArrowCw.X,ptArrowCw.Y),PointF(ptEnd.x,ptEnd.y));//线箭头
	//graphics.DrawLine(&pen_a,PointF(ptArrowCCw.X,ptArrowCCw.Y),PointF(ptEnd.x,ptEnd.y));
	//红色填充三角形箭头
	gs.DrawPolygon(&pen_a, ptTriangle, 3);
	gs.FillPolygon(&brush_a, ptTriangle, 3);
	//三角形尾巴
	//graphics.DrawPolygon(&pen_a, ptTriangle2, 3);
	gs.DrawLine(&pen_a, PointF(ptStart.X, ptStart.Y), ptInterArrowCw);
	gs.DrawLine(&pen_a, PointF(ptStart.X, ptStart.Y), ptInterArrowCCw);
	gs.FillPolygon(&brush_a, ptTriangle2, 3);
}

CMeasureText::CMeasureText(CBaseImage* pImg, const DrawParam& param)
	: CMeasureObj(pImg, param)
{
	m_bDrawLink = FALSE;
	m_nFontSize = 12;
}

void CMeasureText::DrawShape(Gdiplus::Graphics& gs, RECT rc, const DrawParam& param)
{
	if (m_nHitState == -1)
		return;

	PointF ptB, ptE, ptRT, ptLB;
	PointF pt0 = m_vecPoints.at(0);
	PointF pt1 = m_vecPoints.at(1);
	ptB.X = pt0.X < pt1.X ? pt0.X : pt1.X;
	ptB.Y = pt0.Y < pt1.Y ? pt0.Y : pt1.Y;
	ptE.X = pt0.X > pt1.X ? pt0.X : pt1.X;
	ptE.Y = pt0.Y > pt1.Y ? pt0.Y : pt1.Y;

	//ptB = ImageToClient(ptB);
	//ptE = ImageToClient(ptE);
	ptRT.X = ptE.X; ptRT.Y = ptB.Y;
	ptLB.X = ptB.X; ptLB.Y = ptE.Y;

	m_vecCross.clear();
	m_vecCross.push_back(ptB);
	m_vecCross.push_back(ptE);
	m_vecCross.push_back(ptRT);
	m_vecCross.push_back(ptLB);

	Pen pen(colorGreen);
	Pen penPin(colorRed);

	if (m_nHitState == 4)
		pen.SetColor(colorHover);

	if (m_bSel)
		pen.SetColor(colorRed);

	RectF rcRect;
	rcRect.X = ptB.X;
	rcRect.Y = ptB.Y;
	rcRect.Width = ptE.X - ptB.X;
	rcRect.Height = ptE.Y - ptB.Y;

	gs.DrawRectangle(&pen, rcRect);

	// 端点十字
	for (size_t i = 0; i < m_vecCross.size(); i++)
	{
		PointF ptC = m_vecCross.at(i);

		Color color(colorRed);
		if (m_nHitState == i)
			color = colorHover;
		DrawCross(gs, ptC, color);
	}
}

void CMeasureText::DrawText(Gdiplus::Graphics& gs)
{
	int num = m_vecText.size();
	if (num <= 0)
		return;

	Matrix* mtx;
	mtx = m_drawInfo.GetMatrix(m_rc);
	gs.SetTransform(mtx);

	if (m_vecPoints.size() < 2)
		Complete(PointF(0,0));

	int fontSize = m_nFontSize;
	//float newLen = GetLineLen(ImageToClient(m_vecPoints.at(0)), ImageToClient(m_vecPoints.at(1)));
	float newLen = GetLineLen(m_vecPoints.at(0), m_vecPoints.at(1));
	float f = newLen / m_base * 1.25;
	fontSize = m_nFontSize * f;
	fontSize = fontSize < 6 ? 6 : fontSize;

	PointF ptOrg = m_vecPoints.at(0);
	DString txt = m_vecText.at(0);
	Font font(m_Font.GetData(), fontSize);
	RectF rcTxt = GetTextRect(txt, ptOrg, &font);
	SolidBrush brTxt(Color(255, 255, 255));
	gs.DrawString(txt.GetData(), txt.GetLength(), &font, ptOrg, &brTxt);

	gs.ResetTransform();
}

void CMeasureText::AddPoint(Gdiplus::PointF pt)
{
	if (m_vecPoints.size() > 1)
		return;

	m_vecPoints.push_back(pt);
}

void CMeasureText::GetText()
{
	//m_vecText.push_back(_T("测试文字"));
}

void CMeasureText::Complete(Gdiplus::PointF pt)
{
	if (m_vecPoints.size() == 1)
	{
		PointF p0 = ImageToClient(m_vecPoints.at(0));
		GetText();
		if (m_vecText.size() > 0)
		{
			Font font(m_Font.GetData(), m_nFontSize);
			DString txt = m_vecText.at(0);
			RectF rcTxt = GetTextRect(txt, p0, &font);
			PointF p1;
			p1.X = p0.X + rcTxt.Width * 1.15;
			p1.Y = p0.Y + rcTxt.Height;
			p1 = CDisplayerUI::ClientToImage(m_rc, m_drawInfo, p1);
			m_vecPoints.push_back(p1);
			NormalizeRect(m_vecPoints);
			m_base = GetLineLen(ImageToClient(m_vecPoints.at(0)), ImageToClient(m_vecPoints.at(1)));
			m_bComplete = TRUE;

		}
		
	}

}

int CMeasureText::HitTest(Gdiplus::PointF pt, BOOL bPress)
{
	PointF ptI = CDisplayerUI::ClientToImage(m_rc, m_drawInfo, pt);

	m_nHitState = -1;
	for (size_t i = 0; i < m_vecPoints.size(); i++)
	{
		RectF rc = GetPtRect(m_vecPoints.at(i), 1);
		if (rc.Contains(ptI))
		{
			m_nHitState = i;
			return m_nHitState;

		}
	}

	if (m_vecPoints.size() >= 4)
	{
		//PointF ptB = ImageToClient(m_vecPoints.at(0));
		//PointF ptE = ImageToClient(m_vecPoints.at(1));

		PointF ptB = m_vecPoints.at(0);
		PointF ptE = m_vecPoints.at(1);

		RectF rcRect;
		rcRect.X = ptB.X;
		rcRect.Y = ptB.Y;
		rcRect.Width = ptE.X - ptB.X;
		rcRect.Height = ptE.Y - ptB.Y;


		if (rcRect.Contains(ptI))
		{
			m_nHitState = 4;
			if (bPress)
				m_bSel = bPress;
			return m_nHitState;
		}
	}

	return m_nHitState;
}

CMeasureTextR::CMeasureTextR(CBaseImage* pImg, const DrawParam& param)
	: CMeasureText(pImg, param)
{
	m_nFontSize = 20;
}

void CMeasureTextR::GetText()
{
	m_vecText.clear();
	m_vecText.push_back(_T("R"));
}

CMeasureTextL::CMeasureTextL(CBaseImage* pImg, const DrawParam& param)
	: CMeasureText(pImg, param)
{
	m_nFontSize = 20;
}

void CMeasureTextL::GetText()
{
	m_vecText.clear();
	m_vecText.push_back(_T("L"));
}
